"""
白色的RGB值是(255, 255, 255)。
黑色的RGB值是(0, 0, 0)。
"""
from PIL import Image

"""
要在 chrome://dino/ 的游戏中使用Chrome开发者工具查找鼠标所在位置的像素点，你可以遵循以下步骤：
1,启动 chrome://dino/ 游戏:
   在Chrome地址栏输入 chrome://dino/ 并按Enter键开始游戏。点击页面或按空格键使游戏暂停。
   打开Chrome开发者工具:
   右键单击游戏界面，并选择"检查"（Inspect），或直接按F12键。
2,选择Canvas元素:
   在"Elements"面板中，找到与游戏相关的 <canvas> 元素并选中它。通常，这是游戏图像绘制的地方。
3, 转到Console面板:
   在开发者工具的顶部，点击"Console"选项卡，这将允许你执行JavaScript代码。
   添加事件监听器:
    在Console面板中输入以下代码，为Canvas元素添加一个事件监听器，该监听器会在鼠标点击Canvas时输出像素数据：

var canvas = document.querySelector('canvas');
canvas.addEventListener('click', function(event) {
    var rect = canvas.getBoundingClientRect();
    var x = event.clientX - rect.left;
    var y = event.clientY - rect.top;
    var ctx = canvas.getContext('2d');
    var pixel = ctx.getImageData(x, y, 1, 1).data;
    console.log(`Position: (${x}, ${y}), Pixel data: [R=${pixel[0]}, G=${pixel[1]}, B=${pixel[2]}, A=${pixel[3]}]`);
});

点击Canvas上的位置: 现在，点击Canvas上的任意位置，Console面板应该会显示鼠标所在位置的坐标以及该位置的像素数据。
"""


def get_size_of_game(driver):
    """
        获取游戏页面的大小，便于后续参数的调整。
    """
    # 使用JavaScript来获取游戏页面的宽度和高度
    page_width = driver.execute_script("return document.documentElement.scrollWidth;")
    page_height = driver.execute_script("return document.documentElement.scrollHeight;")
    print(f"Dino游戏页面大小为: {page_width}x{page_height}")  # 1530*802
    window_size = driver.get_window_size()
    print('Window size: ', window_size)


def get_width_height_of_canvas(canvas):
    # 获取Canvas的长和宽
    s_width = canvas.get_attribute('width')
    s_height = canvas.get_attribute('height')
    width = int(s_width)
    height = int(s_height)
    print(f"Canvas width: {s_width}, height: {s_height}")
    return width, height


def get_pixels_value(driver, canvas_element, x, y, width, height):
    """
    定义函数以获取Canvas上特定位置的像素值
    使用JavaScript获取像素值
    """
    pixel_value = driver.execute_script("""  
        var canvas = arguments[0];
        var ctx = canvas.getContext('2d');
        var pixel = ctx.getImageData(arguments[1], arguments[2], arguments[3], arguments[4]).data;
        return Array.from(pixel);
        """, canvas_element, x, y, width, height)
    #  初始画布的黑色变为白色
    for j in range(height):
        for i in range(width):
            start_pos = (j * width + i) * 4
            pixel_value[start_pos] = 255 - pixel_value[start_pos]  # 截图后游戏背景为黑色，游戏用到了画布渲染技术。
            pixel_value[start_pos + 1] = 255 - pixel_value[start_pos + 1]
            pixel_value[start_pos + 2] = 255 - pixel_value[start_pos + 2]
            pixel_value[start_pos + 3] = 255 - pixel_value[start_pos + 3]
    return pixel_value


def collision_detection(pixels, width, up_col):
    """
        up_col:pixels里面的起始Y位置从up_col开始。
        碰撞检测
        调用 get_size_of_game 获取的页面为1530*802
        如果此值变化，下面的碰撞检测的矩形坐标需要变化。
        下面是dino的页面HTML代码
        <div role="application" tabindex="0" title="跳！" class="runner-container"
             style="width: 600px; transform: scale(1.46667) translateY(57.5px); height: 150px;">
             <canvas class="runner-canvas" width="600" height="150" style="width: 600px; height: 150px;"></canvas>
             <span class="offline-runner-live-region" aria-live="assertive">游戏已开始。</span>
        </div>
        使用chrome开发者工具，可观察到此div的大小为880*220，而canvas的大小为600*150
        注意：scale(1.46667)， 600*1.46667=880   150*1.46667=220
    :return: true碰到。
    """
    # （startX，endX）为检测区域的宽度。 97,138,192为chrome开发者工具的定位，66,94,131为画布的像素位置。
    # startX很重要，如果它太小，障碍物移动速度快，等到发送跳指令就来不及。如果它太大，又会提前跳。
    startX = 150  # Dino嘴巴最右边的X位置为66(97÷1.46667)。
    endX = 210  # 检测区域的宽度小，检测碰撞速度快，但是整体效率会低些。宽度合适的值有待优化。
    # （startY，endY）为矩形检测区域的高度。同样的，高度小，检测速度快，但是可能漏检。高度合适的值有待优化。
    startY = 100-up_col  # Dino头顶最上边的Y位置为94(138÷1.46667)。飞鸟的高度超过Dino时，Dino没有必要跳，不会发生碰撞。
    endY = 120-up_col    # 水平线上坡度最大的Y位置在127(186÷1.46667)
    collision = False
    for h in range(startY, endY):
        pix_one_line = h * width
        for w in range(startX, endX):
            start_pos = (pix_one_line + w) * 4
            if pixels[start_pos] != 255:   # 游戏原始背景为黑色，前面代码取像素值时已经用255相减。
                collision = True
                # save_canvas_to_png_file(pixels, 600, 150)
                # save_rectangle_canvas_file(pixels, startX, endX, startY, endY, width)  # 调试代码
                break
        if collision:
            break
    return collision


def optimize_collision_detection(pixels, row, col):
    """
        row: 像素点的行数。
        col: 像素点的列数。
    :return: true碰到。
    """
    collision = False
    for h in range(0, col):
        pix_one_line = h * row
        for w in range(0, row):
            start_pos = (pix_one_line + w) * 4
            if pixels[start_pos] != 255:   # 游戏原始背景为黑色，前面代码取像素值时已经用255相减。
                collision = True
                break
        if collision:
            break
    return collision

def save_canvas_to_png_file(pixels, width, height):
    """
        将画布的图像保存到一个png文件
    :param pixels:  一维数组，每四个元素存放一个像素点。
    :param width:   画布的宽
    :param height: 画布的长度
    :return:
    """
    pix_colors = []
    for j in range(height):
        sub_pix = []
        for i in range(width):
            start_pos = (j * width + i) * 4
            sub_pix.append((pixels[start_pos], pixels[start_pos + 1], pixels[start_pos + 2],
                            pixels[start_pos + 3]))
        pix_colors.append(sub_pix)

    # 获取数组的宽度和高度
    c_width = len(pix_colors[0])
    c_height = len(pix_colors)
    # 创建一个空白的RGB图像
    image = Image.new('RGB', (c_width, c_height))
    # 填充图像的每一个像素
    for y in range(c_height):
        for x in range(c_width):
            image.putpixel((x, y), pix_colors[y][x])

    # 保存图像到文件
    image.save('output_image.png')
    # 如果要直接显示图像（需要有图形界面环境）
    # image.show()


def save_rectangle_canvas_file(pixels, startX, endX, startY, endY, width):
    """
        将画布的图像保存到一个png文件
    :param pixels:  一维数组，每四个元素存放一个像素点。
    :param startX: 起始位置X
    :param startY: 起始位置Y
    :param width:   画布的宽
    :return:
    """
    pix_colors = []
    for j in range(startY, endY):
        sub_pix = []
        for i in range(startX, endX):
            start_pos = (j * width + i) * 4
            sub_pix.append((pixels[start_pos], pixels[start_pos + 1], pixels[start_pos + 2],
                            pixels[start_pos + 3]))
        pix_colors.append(sub_pix)
    # 获取数组的宽度和高度
    c_width = len(pix_colors[0])
    c_height = len(pix_colors)
    # 创建一个空白的RGB图像
    image = Image.new('RGB', (c_width, c_height))
    # 填充图像的每一个像素
    for y in range(c_height):
        for x in range(c_width):
            image.putpixel((x, y), pix_colors[y][x])
    # 保存图像到文件
    image.save('part_dino.png')
